package modelo;

import java.util.Observable;
import java.util.Observer;
import extras.xml.*;
import org.jdom.Document;
import org.jdom.Element;
import excepciones.*;

/**
 * la carrera observa la posicion del auto, y se fija si llego a la meta,
 * y observa las ruedas para ver que no se hayan daniado completamente
 */
public class Carrera extends Observable implements SerializableXML<Element>, Observer {

	/**
	 * Jugador actual de la carrera
	 */
	private Jugador jugador;
	
	/**
	 * Pista donde se correra la carrera.
	 */
	private Pista pista;
	
	/**
	 * Indica si la carrera esta pausada.
	 */
	private boolean pausa;
	
	/**
	 * Indica si el jugador gano la carrera.
	 */
	private boolean gano;
	
	/**
	 * El Cronometro que maneja la carrera
	 */
	private Cronometro cronometro = Cronometro.getInstance();
	
	private boolean carreraTerminada = false;
	
	/**
	 * Constructor de la carrera, donde se coloca el auto en la pista. 
	 */
	public Carrera(Jugador jugador, Pista pista) {
		this.jugador = jugador;
		this.pista =  pista;
		this.gano =  false;
		this.pausar();
		/* reinicia los valores del auto y el danio de las ruedas*/
		this.getJugador().getAuto().reiniciar();
		this.getJugador().getAuto().colocarEnPista(this.getPista());
		pista.setCarrera(this);
		this.getJugador().getAuto().getRuedas().setPista(pista);
		
		/* las ruedas observan la pista por la posicion del auto */
		pista.addObserver(this.getJugador().getAuto().getRuedas()); 
		
		/* la carrera observa las ruedas por el danio */
		this.getJugador().getAuto().getRuedas().addObserver(this);
		
	}
	
	/**
	 * Devuelve el Jugador que esta corriendo la carrera. 
	 * @return el jugador humano que esta corriendo la carrera
	 */
	public Jugador getJugador(){
		return this.jugador;
	}
	
	/**
	 * Devuelve la pista en la cual se corre la carrera.
	 * @return la pista donde se corre la carrera
	 */
	public Pista getPista(){
		return this.pista;
	}

	/**
	 * @return verdadero  si la carrera ha finalizado.
	 */
	public boolean termino(){
		return carreraTerminada ;
	}
	
	/**
	 * Indica si la carrera esta pausada.
	 * @return true si la carrera esta pausada y false en caso contrario
	 */
	public boolean estaPausada(){
		return pausa;
	}

	/**
	 * Pausa la carrera.
	 */
	public void pausar() {
		this.pausa = true;
		Cronometro.getInstance().pausar();
	}
	
	/**
	 * Reanuda la carrera.
	 */
	public void reanudar() {
		this.pausa = false;
		Cronometro.getInstance().reanudar();
	}

	/**
	 * finaliza la carrera actual
	 */
	public void finalizar() {
		// deja de correr el timer, y por ende, deja de actualizar a los observadores.
		carreraTerminada = true;
		cronometro.pausar();
		if(gano()){
//			System.out.print("nombre: ");
//			System.out.println(jugador.getNombre());
//			System.out.print("tiempo: ");
//			System.out.println(cronometro.getTiempoEnSegundos());
			pista.getMejoresTiempos().agregar(jugador.getNombre(), cronometro.getTiempoEnSegundos());
//			pista.getMejoresTiempos().imprimir();
		}
		// elimina todos los observadores para dejar todo listo para la proxima carrera
		Cronometro.getInstance().deleteObservers();
		this.getJugador().getAuto().deleteObservers();
		this.getPista().deleteObservers();
		this.getJugador().getAuto().getRuedas().deleteObservers();
		
	}
	
	/**
	 * Inicia la carrera.
	 */
	public void comenzar(){
		Cronometro.getInstance().iniciar(); // comienza a correr el tiempo
		pausa = false;
		carreraTerminada = false;
	}
	
	/**
	 * Devuelve un elemento xml que representa a la carrera.
	 * @return elemento xml que representa a la carrera
	 */
	public Element toXML() {
		Element xmlElement = new Element("carrera");
//		xmlElement.setAttribute(this.premio.toXML().setName("premio"));
//		xmlElement.addContent(getJugadorHumano().toXML().setName("jugador_humano"));
//		xmlElement.addContent(getJugadorMaquina().toXML().setName("jugador_maquina"));
//		xmlElement.addContent(pista.toXML());
		return xmlElement;
	}
	
	/**
	 * Indica si el jugador llego al final de la pista en menos del tiempo de pista.
	 * @return true cuando gano
	 */
	public boolean gano() {
		return gano;
	}
	
	public void update(Observable o, Object args){	
		if (!this.estaPausada() && !this.termino()){
			//se fija que no se hayan daniado totalmente las ruedas
			try{
				if (this.getJugador().getAuto().getRuedas().getDanio() >= 1)
					throw new RuedasRotasException();
			} catch (RuedasRotasException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} /*else
			if (this.termino())
				this.finalizar();*/
	}
	
	
	public void setPista(Pista pista) {
		this.pista = pista;
	}

	public void cargarDesdeXML(Element xmlElement) throws XMLUnserializeException {
//		premio = new Monto(xmlElement.getAttribute("premio"));
//		jugadorHumano = new JugadorHumano(xmlElement.getChild("jugador_humano"));
//		jugadorMaquina = new JugadorMaquina(xmlElement.getChild("jugador_maquina"));
//		pista = new Pista(xmlElement.getChild("pista"));
//		setPausa(true);
//		getJugadorHumano().getAuto().colocarEnLugar(this.getPista());
//		getJugadorMaquina().getAuto().colocarEnLugar(this.getPista());
	}

	public void setGano(boolean gano) {
		this.gano = gano;
	}
}
